<?php
use GatewayClient\Gateway;

class base_model
{
    protected $version; // 版本号
    protected $db; // 数据库实例
    protected $clients = array('app', 'web', 'mobile'); //客户端类型列表
    protected $pageTitle = '';
    protected $client_type = 'web'; //默认客户端类型
    protected $theme = 'default'; //默认网站样式
    protected $time; //当前时间
    protected $microtime = 0;
    protected $post = false;//是否post请求
    protected $ispage = false; //是否页面请求
    protected $usercheck = true;
    protected $user_session = 'USER'; // 用户session名称
    protected $language; //语言；
    protected $isWeb = true;//是否为网页访问
    protected $default_pagesize = 15;
    protected $config = array();
    protected $path = '';
    protected $get_para = '';
    protected $authid = 0; //控制器id
    protected $pagesize = 12; //默认每页显示的数据量
    protected $vcodeSessionName = 'a_s_name';
    protected $currencyName = '金币';
    protected $autosenduserlist = array();
    protected $jsonObj = array(
        'state' => 404,
        'message' => '',
    );
    protected $cashState = array(
        0 => '待提',
        1 => '成功',
        2 => '失败',
    );
    protected $rechargeState = array(
        0 => '待充',
        1 => '成功',
        2 => '失败',
    );
    protected $redState = array(
        0 => '待抢',
        1 => '完成',
        2 => '超时',
    );
    protected $mainnav_group = array(
        0 => '主导航',
        1 => '副导航'
    );
    protected $usertype = array(
        0 => '试玩',
        1 => '会员',
        2 => '代理',
        3 => '内部',
    );
    protected $coin_type_data = array(
        1 => '发红包',
        2 => '抢红包',
        3 => '给玩家发红包',
        4 => '收到玩家发来的红包',
        5 => '手续费',
        6 => '红包超时退回',
        7 => '抢到的红包',
        8 => '门票',
        9 => '(赢家)退回红包',
        10 => '抽水',
        11 => '红包赢利',
        12 => '传红包给玩家',
        13 => '传红包手续费',
        14 => '收到玩家传来的红包',
        15 => '创建红包',
        16 => '预投注余款退回',
        17 => '聊天室发红包',
        18 => '聊天室抢到的红包',
        19 => '退回聊天室红包未抢完',
        20 => '提现',
        21 => '充值',
        22 => '商品兑换',
        23 => '注册赠送',
        24 => '返水',
        25 => '推荐赠送',
        26 => '充值折返',
        27 => '充值赠送',
        28 => '口令红包费用',
        29 => '会员晋级奖励',
        30 => '代理晋级奖励',
        31 => '活动优惠',
        32 => '首冲赠送',
        33 => '手动提出',
        100=> '房主抽成'
    );
    public $scoreliqtype = array(
        1 => '参与红包',
        2 => '签到',
        3 => '兑换',
        4 => '注册',
    );
    protected $redis;
    protected $redisPrefix = array(
        'ONLINES' => 'chat_count_numbers',
        'CRAS' => 'chat_rooms_all', //所有可用的聊天室列表
        'CRWL' => 'chat_rooms_whitelist_', // 聊天室白名单列表
        'CRBL' => 'chat_rooms_blacklist_', // 聊天室黑名单列表
        'CRLP' => 'chat_rooms_for_', // 单个聊天室的参数
        'CRISSUE' => 'chat_issue_for_', // 聊天室红包期号
        'CRISSUEDATA' => 'chat_issue_time_for_', // 聊天室红包期号日期(YMD)
        'GRFC' => 'games_rule_forid_', // 红包游戏规则
        'GLAS' => 'game_list_all', //所有可用状态的游戏
        'GHBS' => 'game_home_banners', // 游戏首页轮播
        'GFID' => 'games_item_forid_', // 游戏的参数不包括赔率
        'GPOP' => 'games_paras_odds_', //游戏的参数及对应的赔率
        'GISSUE' => 'games_issue_', // 红包期数-数据
        'IISSUE' => 'games_doing_', //进行中的单期红包键
        'GOISSUE' => 'games_item_for_', //已完成红包单期数据
        'SPAMS' => 'game_sys_paras_', // 系统参数
        'SOSUM' => 'chat_game_online', // 在线人数
        'NCATE' => 'news_category_', //新闻分类
        'NLIST' => 'news_list_', //新闻列表
        'NITEM' => 'news_item_', //新闻内容
        'PAYWAYS' => 'sys_payways', //支付通道
        'PROFIT' => 'user_profit_', //玩家数据统计
        'UMAILT' => 'user_mail_total_', // 玩家短信统计数量
        'MARQUEE' => 'games_marquee_', // 跑马灯内容
        'UAGENT' => 'game_agent_level_', // 代理等级
        'ULEVEL' => 'game_user_level_', // 用户等级
        'UPLIST' => 'game_user_probability', //概率用户表
        'UAUTOS' => 'games_autosend_userlist', // 机器人
        'LUCONT' => 'game_myuser_', // 我的直属玩家
        'RANKING' => 'ranking_', // 排行榜
        'GCOUNT' => 'game_playing_count', // 进行中的红包数量
        'SMSLINE' => 'game_sms_line', //短信接口
        'ROUNDAVATAR' => 'game_user_avatar', //随机头像列表
        'SGPARAMS' => 'game_send_grab_params_', // 对应游戏的抢发参数
        'MANAGE' => 'management_', //后台数据缓存
    );
    protected $score_type_data = array();
    protected $coin_types = array();


    public function __construct()
    {
        $this->version = time();//VERSION;
        $this->microtime = $this->get_microtime();
        $this->db = core::plus('mysql');
        $this->post = strtolower($_SERVER['REQUEST_METHOD']) === 'post' ? true : false;
        $this->ispage = (array_key_exists('ispage', $_POST) && $_POST['ispage'] === 'true') ? true : false;
        $this->time = time();
        //载入语言
        $this->language = $this->loadlanguage();
        $config_data = $this->db->query("SELECT * FROM `@@params`", 3);
        foreach ($config_data as $v) $this->config[$v['name']] = $v['value'];

        //处理传入参数
        $uri = array_key_exists('REQUEST_URI', $_SERVER) ? $_SERVER['REQUEST_URI'] : '/';
        $uri_info = parse_url($uri);

        $client_type = core::BrowerInfo();
        $this->path = $client_type['path'];
        //var_dump($client_type);
        $client_type = is_array($client_type) && array_key_exists('client_type', $client_type) ? ($client_type['client_type']) : (core::isMobile() ? 'mobile' : 'web');
        $this->client_type = $client_type;

        core::$theme = PATH_ROOT . '/default';
        $this->get_para = explode('/', $uri_info['path'] === '/' ? '/home/' . $client_type . '' : $uri_info['path']);
        if ($client_type == 'web') {
            $this->isWeb = true;
        } else {
            $this->isWeb = false;
        }
        //定义常量
        define('VIEW', PATH_ROOT . '/views/' . $this->theme . '/' . $client_type);
        define('CSS', WEBURL . '/static/' . $this->theme . '/' . $client_type . '/css/');
        define('IMG', WEBURL . '/static/' . $this->theme . '/' . $client_type . '/img/');
        define('SCRIPT', WEBURL . '/static/' . $this->theme . '/' . $client_type . '/script/');
        define('OTHER', WEBURL . '/static/' . $this->theme . '/' . $client_type . '/other');
        define('SOUND', WEBURL . '/static/' . $this->theme . '/' . $client_type . '/sound');

        if ($this->usercheck) $this->user_check_func();
        /*
		foreach ($this->coin_type_data as $vs) {
			foreach ($vs as $k => $v) $this->coin_types[$k] = $v;
		}
        */
        $this->currencyName = $this->config['currencyName'];

        $this->redis = new \Redis();
        $this->redis->connect(REDIS_HOST, REDIS_PORT);
        $this->redis->auth(REDIS_AUTH);

        $this->autosenduserlist = $this->redisGet('games_autosend_userlist');
        if (!$this->autosenduserlist) {
            $sql = "SELECT * FROM `@@autosend`";
            $autodata = $this->db->query($sql, 3);
            $this->redisSet('games_autosend_userlist', $autodata);
            $this->autosenduserlist = $autodata;
        }
    }

    # region 生成唯一订单号
    public function neworderno()
    {
        $beginStr = chr(mt_rand(65, 90));//大写字母
        $orderSn = $beginStr . date('Y') . strtoupper(dechex(date('m'))) . date('d') . substr(time(), -5) . substr(microtime(), 2, 5) . sprintf('%02d', rand(0, 99));
        return $orderSn;
    }
    # endregion

    # region 格式化金币为两位小数
    /**
     * 格式化金币为两位小数
     * @param $coin
     * @return string
     */
    public function formatCoin($coin)
    {
        return number_format($coin, 2, '.', '');
    }
    # endregion

    # region 取出系统设置，按指定$expire的时间长度来缓存
    /*
     * 取出系统设置，按指定$expire的时间长度来缓存
     * @param int $expire 缓存时效
     * @param array return
     */
    protected function getSystemSettings($expire = 86400)
    {
        $this->config = $this->redisGet('systemSettings');
        if (!$this->config) {
            $sql = "select * from `@@params`";
            $this->config = array();
            if ($data = $this->db->query($sql, 3)) {
                foreach ($data as $var) {
                    $this->config[$var['name']] = $var['value'];
                }
            }
            $this->redisSetEx('systemSettings', $this->config, $expire);
        }
        return $this->config;
        /*
        if($expire===null) $expire=$this->expire;
        $file=$this->cacheDir . 'systemSettings';
        if($expire && is_file($file) && filemtime($file)+$expire>$this->time){
            return $this->config=unserialize(file_get_contents($file));
        }

        $sql="select * from `@@params`";
        $this->config=array();
        if($data=$this->db->query($sql,3)){
            foreach($data as $var){
                $this->config[$var['name']]=$var['value'];
            }
        }
        file_put_contents($file, serialize($this->config));
        return $this->config;
        */
    }
    # endregion

    # region 系统毫秒
    protected function get_microtime()
    {
        list($usec, $sec) = explode(' ', microtime());
        return ((float)$usec + (float)$sec);
    }
    # endregion

    # region 格式化数字
    protected function N($str, $strc = "")
    {
        if (floatval($str) == 0) {
            $result = "";
        } else {
            $result = number_format($str, 2);
            if (empty($strc)) $result = str_replace(",", "", $result);
        }
        return $result;
    }
    # endregion

    #region 用户登录检查
    protected function user_check_func()
    {
        $opt = array();
        $url_login = '/user/login';
        if (array_key_exists($this->user_session, $_SESSION) && $_SESSION[$this->user_session]) {
            $this->user = unserialize($_SESSION[$this->user_session]);
            $user_key = session_id();
            $user_sql = "SELECT `isonline`, `state` FROM `@@admin_session` WHERE `uid`={$this->user['uid']} AND `session_key`='$user_key' ORDER BY `id` DESC LIMIT 1";
            $user_info = $this->db->query($user_sql, 2);
            if (!$user_info['isonline'] && $user_info['state'] == 1) {
                $opt = array(
                    'type' => 'error',
                    'text' => '您的账号在别处登陆，您被强迫下线',
                    'auto' => true,
                    'yes' => array(
                        'text' => '重新登录',
                        'func' => '$.reload("' . $url_login . '");',
                    ),
                );
            } else if (!$user_info['isonline']) {
                $opt = array(
                    'type' => 'error',
                    'text' => '由于登陆超时或网络不稳定，您的登录已失效',
                    'auto' => true,
                    'yes' => array(
                        'text' => '重新登录',
                        'func' => '$.reload("' . $url_login . '");',
                    ),
                );
            } else if (!array_key_exists('access_update', $_SESSION) || $_SESSION['access_update'] < $this->time - 15) {
                $id = $this->user['sessionid'];
                $update_sql = "UPDATE `@@admin_session` SET `accesstime`={$this->time} WHERE `id`='$id' LIMIT 1";
                $this->db->query($update_sql, 0);
                $_SESSION['access_update'] = $this->time;
            }
        } else {
            $opt = array(
                'type' => 'error',
                'text' => '您还没有登录',
                'auto' => true,
                'yes' => array(
                    'text' => '登录',
                    'func' => '$.reload("' . $url_login . '");',
                ),
            );
        }
        if (!empty($opt)) {
            unset($_SESSION[$this->user_session]);
            if ($this->post) {
                $this->dialogue($opt);
                exit;
            } else {
                header('Location: ' . $url_login);
                exit;
            }
        }
        //检测权限设置
        $_curPathAuth = $this->path[1] . '_' . $this->path[2];
        //$_curPathAuth = $this->path[2];
        //去除添加、删除、状态、更新、编辑等后缀
        $auth_array = explode('_', $_curPathAuth);
        //var_dump($auth_array);
        $_curPathAuth = str_replace('_add', '', $_curPathAuth);
        $_curPathAuth = str_replace('_edit', '', $_curPathAuth);
        $_curPathAuth = str_replace('_save', '', $_curPathAuth);
        $_curPathAuth = str_replace('_delete', '', $_curPathAuth);
        $_curPathAuth = str_replace('_list', '', $_curPathAuth);
        $_curPathAuth = str_replace('_state', '', $_curPathAuth);
        $_curPathAuth = str_replace('_search_select', '', $_curPathAuth);
        $_curPathAuth = str_replace('_recovery', '', $_curPathAuth);
        $_curPathAuth = str_replace('_killuser', '', $_curPathAuth);
        if (count($auth_array) >= 2) {
            //$_curPathAuth = $auth_array[0] . '_' . $auth_array[1];
            $as = '';
            for ( $i=0; $i < count($auth_array); $i++ ) {
                $as .= $auth_array[$i] . '_';
            }
            $_curPathAuth = substr($as, 0, -1);
        }

        if ($_curPathAuth != 'sys_logout') {
            //查找
            $sql = "SELECT `id`,`title` FROM `@@auth` WHERE `action`='{$_curPathAuth}' LIMIT 1";
            $_auth = $this->db->query($sql, 2);

            $this->authid = intval($_auth['id']);
            $_authid = ',' . intval($_auth['id']) . ',';
            //查找用户组权限列表
            $_user_auth_sql = "select `title`,CONCAT(',',`auths`,',') AS auths FROM `@@auth_user_group` where `id`=" . intval($this->user['usergroup']) . ' limit 1';
            $_user_auth = $this->db->query($_user_auth_sql, 2);
            $_userauths = '0,' . $_user_auth['auths'];
            //$_user_auth = '0,'.$this->user['auths'].',';
            //var_dump($_user_auth);

            if (strpos($_userauths, $_authid) == false) {
                core::error($_user_auth['title'] . '帐号无【' . $_auth['title'] . '】权限！' . $_curPathAuth);
            }
        }
        //与用户资料进行对比

    }
    # endregion

    # region 记录管理员日志
    /**
     * 管理员日志
     * @param $type integer 控制器ID
     * @param $logString string 操作描述
     * @param $extfield0 integer 操作数据行所对应的ID
     * @param $extfield1 string 操作栏目名称
     * $extfield2 array POST OR GET 数据提交表单参数
     */
    public function addLog($type, $logString, $extfield0 = 0, $extfield1 = '')
    {
        $extfield2 = $this->post ? $_POST : $_GET;
        unset($extfield2['id']);
        unset($extfield2['action']);
        unset($extfield2['client_type']);
        unset($extfield2['errorinfoselect']);
        unset($extfield2['content']);
        $extfield2 = json_encode($extfield2);
        if( !$extfield1 ){
            $sql = "SELECT `title` FROM `@@auth` WHERE `id`='{$type}' LIMIT 1";
            $_auth = $this->db->query($sql, 2);
            $extfield1 = $_auth['title'];
        }
        $log = array(
            'uid' => $this->user['uid'],
            'username' => $this->user['username'],
            'type' => $type,
            'actionTime' => $this->time,
            'actionIP' => $this->ip(true),
            'action' => $logString,
            'extfield0' => $extfield0,
            'extfield1' => $extfield1,
            'extfield2' => $extfield2,
        );
        return $this->db->insert('@@admin_log', $log);
    }
    # endregion

    # region 生成当前游戏类型的期号
    public function getIssue($gameid)
    {
        global $db;
        global $redis;
        global $utility;

        $redis_key = 'games_issue_' . $gameid . '_count';
        $redis_key_date = 'games_issue_' . $gameid . '_createdate';
        $issue_nums_len = 6;
        $issue_nums = 1000000; //要保留的期号长度,当前数字少一位数
        $nowdate = strval(date('Ymd'));
        $beginTimes = mktime(0, 0, 0, date('m'), date('d'), date('Y'));
        $endTimes = $beginTimes + 86400;
        $sql = "SELECT (COUNT(1)+1) AS _TOTAL FROM `rp_bets` WHERE `begintimes`>={$beginTimes} AND `begintimes`<={$endTimes} AND `gameid`={$gameid}";
        $issue_db = $this->db->query($sql, 2);
        $sourceNumber = $issue_db['_TOTAL'];
        $newNumber = substr(strval($sourceNumber + $issue_nums), 1, 6);
        //}
        $issue = date('Ymd') . $gameid . $newNumber;
        # 写入Redis
        $this->redisSet($redis_key, $issue);
        $this->redisSet($redis_key_date, $nowdate);
        return $issue;
    }
    # endregion

    # region 分页相关
    /*
    * 取出当前分类的最大排序数字
    */
    protected function table_maxsort($table, $field, $where)
    {
        $sql = "SELECT IFNULL(MAX(`{$field}`),0)+1 AS _MaxSort FROM `{$table}` WHERE {$where}";
        $data = $this->db->query($sql, 2);
        return $data['_MaxSort'];
    }

    // 获取当前页码
    protected function get_page($get = true)
    {
        $para = $get ? (isset($_GET['page']) ? $_GET['page'] : 1) : (isset($_POST['page']) ? $_POST['page'] : 1);
        return (array_key_exists('page', $_GET) && core::plus('validate')->number($para)) ? intval($para) : 1;
    }

    // 获取数据列表最大页码
    protected function get_maxpage($psize, $total)
    {
        $page_max = $total > 0 && $psize > 0 ? ceil($total / $psize) : 1;
        return $page_max ? $page_max : 1;
    }

    protected function iff($if, $true, $false = '')
    {
        return $if ? $true : $false;
    }

    // 分页-页码数字
    protected function page_url($page, $page_url, $flag = '{page}')
    {
        return str_replace(urlencode($flag), $page, $page_url);
    }
    # endregion

    #region 取得客户端的IP地址
    protected function ip($return_long = false)
    {
        $ip = '';
        if (isset($HTTP_SERVER_VARS)) {
            if (array_key_exists('HTTP_X_FORWARDED_FOR', $HTTP_SERVER_VARS)) {
                $ip = $HTTP_SERVER_VARS['HTTP_X_FORWARDED_FOR'];
            } else if (array_key_exists('HTTP_CLIENT_IP', $HTTP_SERVER_VARS)) {
                $ip = $HTTP_SERVER_VARS['HTTP_CLIENT_IP'];
            } else if (array_key_exists('REMOTE_ADDR', $HTTP_SERVER_VARS)) {
                $ip = $HTTP_SERVER_VARS['REMOTE_ADDR'];
            }
        }
        if (empty($ip)) {
            if (array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER)) {
                $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
            } else if (array_key_exists('HTTP_CLIENT_IP', $_SERVER)) {
                $ip = $_SERVER['HTTP_CLIENT_IP'];
            } else if (array_key_exists('REMOTE_ADDR', $_SERVER)) {
                $ip = $_SERVER['REMOTE_ADDR'];
            } else {
                $ip = '0.0.0.0';
            }
        }
        if (strpos($ip, ',') !== false) {
            $ip = explode(',', $ip, 2);
            $ip = current($ip);
        }
        return $return_long ? bindec(decbin(ip2long($ip))) : $ip;
    }
    # endregion

    # region 取得浏览器信息
    protected function get_browser()
    {
        $flag = $_SERVER['HTTP_USER_AGENT'];
        $para = array();
        if (preg_match('/Windows[\d\. \w]*/', $flag, $match)) $para['os'] = $match[0]; // 检查操作系统
        if (preg_match('/Chrome\/[\d\.\w]*/', $flag, $match)) { // 检查Chrome
            $para['browser'] = $match[0];
        } else if (preg_match('/Safari\/[\d\.\w]*/', $flag, $match)) { // 检查Safari
            $para['browser'] = $match[0];
        } else if (preg_match('/MSIE [\d\.\w]*/', $flag, $match)) { // IE
            $para['browser'] = $match[0];
        } else if (preg_match('/Opera\/[\d\.\w]*/', $flag, $match)) { // opera
            $para['browser'] = $match[0];
        } else if (preg_match('/Firefox\/[\d\.\w]*/', $flag, $match)) { // Firefox
            $para['browser'] = $match[0];
        } else if (preg_match('/OmniWeb\/(v*)([^\s|;]+)/i', $flag, $match)) { // OmniWeb
            $para['browser'] = $match[2];
        } else if (preg_match('/Netscape([\d]*)\/([^\s]+)/i', $flag, $match)) { // Netscape
            $para['browser'] = $match[2];
        } else if (preg_match('/Lynx\/([^\s]+)/i', $flag, $match)) { // Lynx
            $para['browser'] = $match[1];
        } else if (preg_match('/360SE/i', $flag, $match)) { // 360SE
            $para['browser'] = '360安全浏览器';
        } else if (preg_match('/SE 2.x/i', $flag, $match)) { // 搜狗
            $para['browser'] = '搜狗浏览器';
        } else {
            $para['browser'] = 'unkown';
        }
        return $para;
    }
    # endregion

    # region 分享、HTML 及 替换关键字
    protected function baidu_share()
    {
        $html = '<span class="bdsharebuttonbox fr">';
        $html .= '<a href="#" class="bds_more" data-cmd="more"></a>';
        $html .= '<a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间"></a>';
        $html .= '<a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博"></a>';
        $html .= '<a href="#" class="bds_tqq" data-cmd="tqq" title="分享到腾讯微博"></a>';
        $html .= '<a href="#" class="bds_renren" data-cmd="renren" title="分享到人人网"></a>';
        $html .= '<a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信"></a>';
        $html .= '</span>';
        $html .= '<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName(\'head\')[0]||body).appendChild(createElement(\'script\')).src=\'http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion=\'+~(-new Date()/36e5)];</script>';
        return $html;
    }

    protected function clearHtml($string)
    {
        $string = strip_tags($string);
        return $string;
    }

    protected function reHtmlKeys($string)
    {
        $string = preg_replace('/src="\//', 'src="' . $this->config['imglink'], $string);
        $string = str_replace("//upload/", "/", $string);
        $string = str_replace("/upload/", "/", $string);
        //$string = str_replace("http:/","://",$string);
        $string = str_replace('{webName}', $this->config['webName'], $string);
        if (core::isMobile()) {
            $string = str_replace("src=", "data-lazyload=", $string);
        } else {
            $string = str_replace("src=", "class=\"lazy\" data-original=", $string);

        }
        return $string;
    }

    protected function imgs($string, $resize = 0, $width = '', $height = '')
    {
        $string = strtolower($this->config['imglink'] . $string);
        $string = str_replace("//upload/", "/", $string);
        $string = str_replace("/upload/", "/", $string);
        if ($resize) {
            $string = str_replace(".jpg", '!' . $width . '!' . $height . ".jpg", $string);
            $string = str_replace(".png", '!' . $width . '!' . $height . ".png", $string);
            $string = str_replace(".gif", '!' . $width . '!' . $height . ".gif", $string);
            $string = str_replace(".bmp", '!' . $width . '!' . $height . ".bmp", $string);
        }
        //$string = str_replace(":/","://",$string);
        return $string;
    }
    # endregion

    # region post校验
    protected function check_post()
    {
        if (!$this->post) core::__403('-请求类型错误');
    }
    # endregion

    # region ajax加载
    protected function ajax()
    {
        $this->display('index', array('load_self' => true));
    }
    # endregion

    # region 加载语言包
    protected function loadlanguage($language = 'cn')
    {
        /* 载入语言文件 */
        return include(PATH_ROOT . '/languages/' . $language . '.php');
    }
    # endregion

    # region 前端交互相关
    /**
     * @name 前台对话框交互
     * @param array opt 配置数组
     *    |-- type: error|success
     *    |-- text: 提示文本
     *    |-- auto: true|false 是否自动关闭(如果有确认选项，关闭时执行确认选项内容)
     *    |-- yes: 确认选项内容
     *        |-- text: 确认文本
     *        |-- func: 点击确认时执行函数(没有则默认为关闭对话框)
     *    |-- no: 取消选项内容
     *        |-- text: 取消文本
     *        |-- func: 点击取消时执行函数(没有则默认为关闭对话框)
     */
    protected function dialogue($opt)
    {
        switch ($this->client_type) {
            case 'web':
                header('X-Error-Message: dialogue');
                echo json_encode($opt);
                break;
            case 'api':
                $opt['state'] = $opt['type'] == 'success' ? 200 : 404;
                $opt['message'] = $opt['text'];
                echo json_encode($opt);
                break;
            case 'mobile':
                $opt['state'] = $opt['type'] == 'success' ? 200 : 404;
                $opt['message'] = $opt['text'];
                echo json_encode($opt);
                break;
            default:
                $opt['state'] = $opt['type'] == 'success' ? 200 : 404;
                $opt['message'] = $opt['text'];
                echo json_encode($opt);
                break;
        }
        exit;
    }

    protected function alert($message = '', $gotourl = '', $autoclose = true)
    {
        $this->dialogue(array(
            'type' => 'success',
            'text' => (empty($message) ? "操作成功" : $message),
            'auto' => $autoclose,
            'yes' => array(
                'text' => '返回',
                'func' => 'JumpMainFrame("' . $gotourl . '");',
            ),
        ));
    }
    # endregion

    # region 加载页面显示模板
    /**
     * @name 模板加载
     * @param string tpl_name 模板名称
     * @param array args 模板参数
     */
    protected function display($tpl_name, $args = array(), $__expire = 0)
    {
        switch ($this->client_type) {
            case 'web':
                extract($args);
                $viewFile = PATH_ROOT . '/views/' . $this->theme . '/' . $this->client_type . '/' . $tpl_name . '.view.php';
                require($viewFile);
                break;
            case 'api':
            case 'mobile':
            default:
                echo json_encode($args);
                break;
        }

    }
    # endregion

    # region 压缩输出的HTML代码
    protected function compress_html($string)
    {
        return ltrim(rtrim(preg_replace(array("/> *([^ ]*) *</", "//", "'/\*[^*]*\*/'", "/\r\n/", "/\n/", "/\t/", '/>[ ]+</'), array(">\\1<", '', '', '', '', '', '><'), $string)));
    }
    # endregion

    # region 记录资金帐变(请在一个事务里使用)
    protected function set_coin($log)
    {
        $default = array(
            'uid' => (array_key_exists('uid', $log) ? $log['uid'] : 0),
            'gameid' => (array_key_exists('gamid', $log) ? $log['gameid'] : 0),
            'coin' => (array_key_exists('coin', $log) ? $log['coin'] : 0),
            'liqtype' => (array_key_exists('liqtype', $log) ? $log['liqtype'] : 1),
            'ex1' => (array_key_exists('ex1', $log) ? $log['ex1'] : ''),
            'ex2' => (array_key_exists('ex2', $log) ? $log['ex2'] : ''),
            'ex3' => (array_key_exists('ex3', $log) ? $log['ex3'] : ''),
        );
        /*
        $sql = 'call setCoin(';
        foreach ($default as $k => $v) {
            $val = (array_key_exists($k, $log) && $log[$k]) ? $log[$k] : $v;
            if ($v !== 0) $val = "'$val'";
            $sql .= $val.',';
        }
        $sql = substr($sql, 0, -1).')';
        $this->db->query($sql, 0);
        */
        $db_ym = date('Ym');
        try {
            //$this->db->beginTrans();
            $sql = 'UPDATE `' . DB_PREFIX . 'users` SET `coin` = `coin` + ' . $default['coin'] . ' WHERE `uid` = ' . $default['uid'] . ' LIMIT 1';
            if ($default['liqtype'] == 24) {
                $sql = 'UPDATE `@@users` SET `coin` = `coin` + ' . $default['coin'] . ', `backtotal` = `backtotal` + ' . $default['coin'] . ' WHERE `uid` = ' . $default['uid'] . ' LIMIT 1';;
            }
            $this->db->query($sql, 1);

            $sql = 'SELECT `coin`,`usertype`,`agentlevel`,`backtotal`,`betcoin`,`userlevel` FROM `' . DB_PREFIX . 'users` WHERE `uid`=' . $default['uid'] . ' LIMIT 1';
            $user = $this->db->query($sql, 2);

            # 添加资金流动日志
            $_coinlog = array(
                'gameid' => $default['gameid'],
                'uid' => $default['uid'],
                'coin' => $default['coin'],
                'usercoin' => $user['coin'],
                'times' => time(),
                'liqtype' => $default['liqtype'],
                'ex1' => $default['ex1'],
                'ex2' => $default['ex2'],
                'ex3' => $default['ex3'],
                'usertype' => $user['usertype'],
            );
            $this->table_row_save(DB_PREFIX . 'coinlog_' . $db_ym, $_coinlog);

            # 添加赠送日志
            /*
            if ($default['liqtype'] == 23) {
                $_givecoinlog = array(
                    'gameid' => $default['gameid'],
                    'uid' => $default['uid'],
                    'coin' => $default['coin'],
                    'usercoin' => $user['coin'],
                    'times' => time(),
                    'liqtype' => $default['liqtype'],
                    'ex1' => $default['ex1'],
                    'ex2' => $default['ex2'],
                    'ex3' => $default['ex3'],
                    'usertype' => $user['usertype'],
                    'state' => 1,
                );
                $this->table_row_save(DB_PREFI . 'givecoinlog', $_givecoinlog);
            }
            if ($default['liqtype'] == 25 OR $default['liqtype'] == 27) {
                $_givecoinlog = array(
                    'gameid' => $default['gameid'],
                    'uid' => $default['uid'],
                    'coin' => $default['coin'],
                    'usercoin' => $user['coin'],
                    'times' => time(),
                    'liqtype' => $default['liqtype'],
                    'ex1' => $default['ex1'],
                    'ex2' => $default['ex2'],
                    'ex3' => $default['ex3'],
                    'usertype' => $user['usertype'],
                    'state' => 0,
                );
                $this->table_row_save(DB_PREFIX . 'givecoinlog', $_givecoinlog);
            }
            */
            # 处理代理的升级
            if ($default['liqtype'] == 24) {
                $agent = $this->db->query('SELECT `lid`,`backtotal` INTO _agentuplid,_backtotal FROM `' . DB_PREFIX . 'agentlevel` WHERE `lid` > ' . $user['agentlevel'] . ' LIMIT 1', 2);
                if ($user['backtotal'] >= $agent['backtotal']) {
                    $this->db->query('UPDATE ' . DB_PREFIX . 'users SET `agentlevel`=' . $agent['lid'] . ' WHERE `uid`=' . $default['uid'] . ' LIMIT 1', 1);
                }
            }
            # 统计用户的充值总量
            if ($default['liqtype'] == 21 || $default['liqtype'] == 31) {
                # 更新用户的充值总金额
                $sql = "UPDATE `@@users` SET `recharge`=`recharge`+" . $default['coin'] . " WHERE `uid`=" . $default['uid'] . " LIMIT 1";
                $this->db->query($sql, 1);
            }
            # VIP升级
            /*
            $vip = $this->db->query('SELECT `lid`,`title`,`cointotal` FROM `' . DB_PREFIX . 'userlevel` WHERE `lid`>' . $user['userlevel'] . ' LIMIT 1',2);
            if ($user['betcoin'] >= $vip['cointotal']) {
                $this->db->query('UPDATE `' . DB_PREFIX . 'users` SET `userlevel` = ' . $vip['lid'] . ' WHERE `uid` = ' . $default['uid'] . ' LIMIT 1',1);
            }
            */
            //$this->db->commitTrans();
        } catch (PDOException $e) {
            echo $e->getMessage();
            //$this->db->rollBackTrans(); // 执行失败，事务回滚
        }
    }
    # endregion

    # region 记录积分帐变(请在一个事务里使用)
    protected function set_score($log)
    {
        $default = array(
            'uid' => (array_key_exists('uid', $log) ? $log['uid'] : 0),
            'gameid' => (array_key_exists('gamid', $log) ? $log['gameid'] : 0),
            'score' => (array_key_exists('score', $log) ? $log['score'] : 0),
            'liqtype' => (array_key_exists('liqtype', $log) ? $log['liqtype'] : 1),
            'ex1' => (array_key_exists('ex1', $log) ? $log['ex1'] : ''),
            'ex2' => (array_key_exists('ex2', $log) ? $log['ex2'] : ''),
            'ex3' => (array_key_exists('ex3', $log) ? $log['ex3'] : ''),
        );
        /*
        $sql = 'call setScore(';
        foreach ($default as $k => $v) {
            $val = (array_key_exists($k, $log) && $log[$k]) ? $log[$k] : $v;
            if ($v !== 0) $val = "'$val'";
            $sql .= $val.',';
        }
        $sql = substr($sql, 0, -1).')';
        $this->db->query($sql);
        */
        try {
            //$this->db->beginTrans();
            $this->db->query('UPDATE `' . DB_PREFIX . 'users` SET `score` = `score` + ' . $default['score'] . ' WHERE `uid` = ' . $default['uid'] . ' LIMIT 1', 1);
            $user = $this->db->query('SELECT `score`,`usertype` FROM `' . DB_PREFI . 'users` WHERE `uid`=' . $default['uid'] . ' LIMIT 1', 2);
            # 添加流动日志
            $_givecoinlog = array(
                'gameid' => $default['gameid'],
                'uid' => $default['uid'],
                'score' => $default['score'],
                'userscore' => $user['score'],
                'times' => time(),
                'liqtype' => $default['liqtype'],
                'ex1' => $default['ex1'],
                'ex2' => $default['ex2'],
                'ex3' => $default['ex3'],
                'usertype' => $user['usertype'],
            );
            $this->table_row_save(DB_PREFI . 'givecoinlog', $_givecoinlog);
            //$this->db->commitTrans();
        } catch (PDOException $e) {
            //$this->db->rollBackTrans(); // 执行失败，事务回滚
        }

    }
    # endregion

    # region 生成随机长度的数字
    protected function randNumber($len)
    {
        //$chars='ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz';
        $chars = '0123456789';
        $string = time();
        for ($len; $len >= 1; $len--) {
            $position = rand() % strlen($chars);
            $position2 = rand() % strlen($string);
            $string = substr_replace($string, substr($chars, $position, 1), $position2, 0);
        }
        return $string;
    }
    # endregion

    # region 生成随机长度的数字、字母组合
    /*
     * 函数encrypt($string,$operation,$key)
     * @param string $string 需要加密解密的字符串
     * @param string $operation 判断是加密还是解密，E表示加密，D表示解密；
     * @param string $key 密匙。
     */
    public function randString($length = 4)
    {
        // 密码字符集，可任意添加你需要的字符
        $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        $password = '';
        for ($i = 0; $i < $length; $i++) {
            // 这里提供两种字符获取方式
            // 第一种是使用 substr 截取$chars中的任意一位字符；
            // 第二种是取字符数组 $chars 的任意元素
            // $password .= substr($chars, mt_rand(0, strlen($chars) – 1), 1);
            $password .= $chars[mt_rand(0, strlen($chars) - 1)];
        }
        return $password;
    }
    # endregion

    # region 查找某个KEY的值是否存在于多维数组中
    public function deep_in_array($value, $key, $array)
    {
        foreach ($array as $item) {
            if (!is_array($item)) {
                if ($item == $value) {
                    return true;
                } else {
                    continue;
                }
            }
            /*
            if(in_array($value, $item)) {
                return $item;
            } else if($this->deep_in_array($value, $key, $item)) {
                return $item;
            }
            */
            foreach ($item as $k => $v) {
                if ($key == $k && $value == $v) {
                    return true;
                } else {
                    continue;
                }
            }
        }
        return false;
    }
    # endregion

    # region 加密解密字符串
    public function encrypt($string, $operation, $key = '')
    {
        $key = md5($key);
        $key_length = strlen($key);
        $string = $operation == 'D' ? base64_decode($string) : substr(md5($string . $key), 0, 8) . $string;
        $string_length = strlen($string);
        $rndkey = $box = array();
        $result = '';
        for ($i = 0; $i <= 255; $i++) {
            $rndkey[$i] = ord($key[$i % $key_length]);
            $box[$i] = $i;
        }
        for ($j = $i = 0; $i < 256; $i++) {
            $j = ($j + $box[$i] + $rndkey[$i]) % 256;
            $tmp = $box[$i];
            $box[$i] = $box[$j];
            $box[$j] = $tmp;
        }
        for ($a = $j = $i = 0; $i < $string_length; $i++) {
            $a = ($a + 1) % 256;
            $j = ($j + $box[$a]) % 256;
            $tmp = $box[$a];
            $box[$a] = $box[$j];
            $box[$j] = $tmp;
            $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
        }
        if ($operation == 'D') {
            if (substr($result, 0, 8) == substr(md5(substr($result, 8) . $key), 0, 8)) {
                return substr($result, 8);
            } else {
                return '';
            }
        } else {
            return str_replace('=', '', base64_encode($result));
        }
    }
    # endregion

    # region 检测字符串中包含大小写字符的个数
    /*
     * 检测字符串中包含大小写字符的个数
     * @param string $strings 要检测的字符串
     * @param array $result 返回检测结果数组（0=>大写个数,1=>小写个数）
     */
    protected function up_low_sizeof($strings = '')
    {
        $result = array(0 => 0, 1 => 0);
        if (!empty($strings)) {
            preg_match_all('#(?<up>[A-Z]{1})#', $strings, $a);
            $result[0] = sizeof($a['up']); //大写字母个数
            preg_match_all('#(?<low>[a-z]{1})#', $strings, $a);
            $result[1] = sizeof($a['low']); //小写字母个数
        }
        return $result;
    }
    # endregion

    # region 检测一维数组中是否包含KEY这个键
    /*
    * 检测数组中是否包含KEY这个键
    * @param string $key 键名
    * @param array $arr 待检测的数组
    * @param string $dataType 返回值的类型 默认是数值型
    * @param object $result 返回按$isNumeric指定的类型值
    */
    protected function existsKeyInArray($key, $arr, $dataType = 'N', $default = 0)
    {
        $result = '';
        if (is_array($arr) && count($arr) > 0 && array_key_exists($key, $arr)) {
            switch ($dataType) {
                case 'N':
                    $result = intval($arr[$key]);
                    break;
                case "S": //字符型
                    $result = strval($arr[$key]);
                    break;
                case 'D': //日期型 2017-10-11
                    $result = date('Y-m-d', strtotime($arr[$key]));
                    break;
                case 'F': //货币数字
                    $result = floatval($arr[$key]);
                    break;
            }
        } else {
            switch ($dataType) {
                case 'N':
                    $result = $default ? $default : 0;
                    break;
                case "S": //字符型
                    $result = $default ? $default : '';
                    break;
                case 'D': //日期型 2017-10-11
                    $result = $default ? $default : '';
                    break;
                case 'F': //货币数字
                    $result = $default ? $default : 0;
                    break;
            }
        }
        return $result;
    }
    # endregion


    # region SQL语句执行块
    /*
	 * 统计数据行数
	 * @param string $sql 执行的统计SQL语句
	 */
    protected function totalDataRowsCount($sql)
    {
        $sql_total = str_replace('~field~', 'COUNT(1) AS __total', $sql);
        $sql_total = str_replace('~limit~', '', $sql_total);
        $sql_total = str_replace('~order~', '', $sql_total);
        if (ISDEBUG && ISSHOWSQL) {
            echo '统计SQL语句：' . $sql_total . '<br />';
        }
        $db_total = $this->db->query($sql_total, 2);
        $total = $db_total['__total'];
        if (ISDEBUG && ISVARDUMP) {
            echo '统计SQL结果：' . $total . '<br />';
        }
        return $total;
    }

    /*
	 * 统计数据行数
	 * @param string $sql 执行的统计SQL语句
	 */
    protected function totalFieldsCount($sql, $fields)
    {
        $sql_total = str_replace('~field~', $fields, $sql);
        $sql_total = str_replace('~limit~', '', $sql_total);
        $sql_total = str_replace('~order~', '', $sql_total);
        $db_total = $this->db->query($sql_total, 2);
        return $db_total;
    }

    /*
     * 按SQL语句来取数据
     * @param string $sql 执行的SQL语句
     * @param array $args 参数数组，各项数值请参阅以下说明
     * $field string 要搜索的字段
     * $skip int 搜索当前的开始页数
     * $pagesize int 每页显示的行数
     * $order SQL的ORDER条件
     */
    protected function getTableRows($sql, $args)
    {
        if (ISDEBUG) {
            echo '<div class="debuginfo">';
        }
        $total = $this->totalDataRowsCount($sql);
        $skip = (intval($args['page_current']) - 1) * $args['pagesize'];
        $pagesize = intval($args['pagesize']);

        $sql = str_replace('~field~', $args['field'], $sql);
        $sql = str_replace('~limit~', 'LIMIT ' . $skip . ',' . $pagesize, $sql);
        $sql = str_replace('~order~', $args['order'], $sql);
        if (ISDEBUG && ISSHOWSQL) {
            echo '取数SQL语句：' . $sql . '<br />';
        }
        $datas = $this->db->query($sql, 3);
        if (ISDEBUG && ISVARDUMP) {
            if (!$datas) {
                echo '<font color="red">没有任何数据</font><br />';
            } else {
            
            }
        }
        if (ISDEBUG) {
            echo '</div>';
        }
        return array(
            'datas' => $datas,
            'total' => $total,
        );
    }

    /*
    * 更新状态（状态字段固定为 state）
    * @param string $table 待更新的表格
    * @param int $id 分类ID
    */
    protected function update_state($table, $id, $field = 'state')
    {
        $sql = "UPDATE `{$table}` SET `{$field}`=ABS(`{$field}`-1) WHERE `id`={$id}";
        $result = $this->db->query($sql, 0);
        return $result;
    }

    /*
     * 保存新增或编辑的数据
     * @param string $table 要操作的表名
     * @param array $para 表对应的字段列表
     * @param array $update_args 更新表时的WHERE条件表达式
     * @param bool $edit 新增或编辑状态,默认新增
     */
    public function table_row_save($table, $para, $update_args = null, $edit = false)
    {
        $result = 0;
        if ($edit) {
            $result = $this->db->update($table, $para, $update_args);
        } else {
            $result = $this->db->insert($table, $para);
        }
        return $result;
    }

    /*
     * 替换或插入新行
     * @param string $table 表名
     * @param array $para 字段及对应的值
     * @param int return
     */
    public function table_row_save_replace($table, $para)
    {
        return $this->db->replace($table, $para);
    }

    /*
     * 取出数据行
     * @param string $table 表名
     * @param string $field 要拉取的字段列表
     * @param array $where 数据行的条件
     * @param array return
     */
    public function getRow($table, $field, $where = array())
    {
        return $this->db->getRow($table, $field, $where);
    }
    # endregion

    #region 输出选项切换按钮
    /*
     * 输出选项切换按钮
     * @param string $basepath 链接基本路径URL
     * @param int $id 数据行自增ID
     * @param string $fieldname 字段名
     * @param string $fieldvalue 字段值
     * @param int $page_current 当前页
     * @param string $page_url 在controller中http_build_query($page_args)后的值
     */
    public function toggleButton($basepath, $id, $fieldname, $fieldValue, $page_current, $page_url)
    {
        $html = '<a href="' . $basepath . '_state?id=' . $id;
        $html .= '&' . $this->page_url($page_current, $page_url) . '&field=' . $fieldname . '" target="ajax" func="loadpage" ';
        $html .= 'class="upbutton state' . $fieldValue . '">';
        $iClass = ($fieldValue ? '<i class="icon-ok"></i>' : '<i class="icon-cancel"></i>');
        $html .= $iClass . '</a>';
        return $html;
    }
    # endregion

    # region 格式化日期时间
    /**
     * 格式化时间截 - 聊天时间展示
     * @param $times int 时间截
     * @return false|string
     */
    public function formatTimes($times)
    {
        //$times = strtotime($times);
        $w_begin = mktime(0, 0, 0, date("m"), date("d") - date("w") + 1, date("Y"));
        $w_end = mktime(0, 0, 0, date("m"), date("d") - date("w") + 7, date("Y"));

        $wu_begin = mktime(0, 0, 0, date('m'), date('d') - date('w') + 1 - 7, date('Y'));
        $wu_end = mktime(0, 0, 0, date('m'), date('d') - date('w') + 7 - 7 + 1, date('Y'));

        $result = date('Y-m-d- H:i:s', $times);
        $limit = time() - $times;

        $day_begin = strtotime(date('Y-m-d', time()));
        $day_end = $day_begin + 24 * 3600;

        if ($day_begin < $times && $day_end > $times) {
            $result = date('H:i:s', $times);
        } elseif (($day_begin - 86400) < $times && ($day_end - 86400) > $times) {
            //昨天
            $result = '昨天 ' . date('H:i:s', $times);
        } elseif (($day_begin - 86400 - 86400) < $times && ($day_end - 86400 - 86400) > $times) {
            //前天
            $result = '前天 ' . date('H:i:s', $times);
        } elseif ($times > $w_begin && $times < $w_end) {
            //本周
            $w = "星期" . mb_substr("日一二三四五六", date("w", $times), 1, "utf-8");
            $result = $w . ' ' . date('H:i:s', $times);
        } elseif ($times > $wu_begin && $times < $wu_end) {
            //上周
            $w = "上周" . mb_substr("日一二三四五六", date("w", $times), 1, "utf-8");
            $result = $w . ' ' . date('H:i:s', $times);
        } else {
            $result = date('Y-m-d H:i:s', $times);
        }
        return $result;
    }
    # endregion

    # region 给所有APP推送通知更新缓存
    public function pushUpdatecache()
    {
        $result = array(
            'state' => 200,
            'cmd' => 'updatecache',
        );
        Gateway::sendToGroup('public', json_encode($result));
    }
    # endregion

    # region 给玩家推送信息
    public function pushClient($client_uno, $args)
    {
        if ($client_uno == 'all') {
            \GatewayClient\Gateway::sendToAll(json_encode($args));
            $this->dialogue(array(
                'type' => 'success',
                'text' => "给所有玩家推送成功",
                'auto' => true,
                'yes' => array(
                    'text' => '我知道了',
                ),
            ));
        } else {
            \GatewayClient\Gateway::sendToUid('P' . $client_uno, json_encode($args));
            $this->dialogue(array(
                'type' => 'success',
                'text' => "给玩家[{'P'.$client_uno}]推送成功",
                'auto' => true,
                'yes' => array(
                    'text' => '我知道了',
                ),
            ));
        }
    }
    # endregion

    # region Redis操作

    /**
     * 取Redis的值
     * @param $Redis object redis对象
     * @param $key string 要取值的redis字段名
     * @return mixed string|ing|array
     */
    public function redisGet($key)
    {
        $value = $this->redis->get($key);
        $value_serl = @unserialize($value);
        if (is_object($value_serl) || is_array($value_serl)) {
            return $value_serl;
        }
        return $value;
    }

    /**
     * 设置Redis数据
     * @param $Redis object redis对象
     * @param $key string 字段名
     * @param $value key对应的值（string|int|array）
     * @return mixed
     */
    public function redisSet($key, $value)
    {
        if (is_object($value) || is_array($value)) {
            $value = serialize($value);
        }
        return $this->redis->set($key, $value);
    }

    /**
     * 设置有时效性的Redis数据
     * @param $Redis object redis对象
     * @param $key string 字段名
     * @param $value key对应的值（string|int|array）
     * @param $value int 过期时间（秒）
     * @return mixed
     */
    public function redisSetEx($key, $value, $expire = 86400)
    {
        if (is_object($value) || is_array($value)) {
            $value = serialize($value);
        }
        return $this->redis->setex($key, $expire, $value);
    }

    /**
     * 检测LIST虽否存在对应的值
     * @param $redis object Redis对象
     * @param $key string 要查找的Redis键名
     * @param $value string 要检测的键值
     * @param int $Addition_subtraction 统计列表时是否加减总数
     * @return bool
     */
    public function existsRedisKey($key, $value)
    {
        $isHaveNuo = false;
        $_total = $this->redis->llen($key);
        $redis_key_index = 0;
        $redis_key_count = $_total;
        while ($redis_key_index < $redis_key_count) {
            $redis_key_item = $this->redis->lindex($key, $redis_key_index);
            if ($redis_key_item == $value) {
                $isHaveNuo = true;
            }
            $redis_key_index++;
        }
        return $isHaveNuo;
    }

    public function roundFromRedisKey($key)
    {
        $key_count = $this->redis->llen($key);
        $key_index = mt_rand(0, $key_count);
        $result = $this->redis->lindex($key, $key_index);
        # 从KEY中删除
        $this->redis->lrem($key, $key_index, 1);
        return $result;
    }
    # endregion

    # region 代理等级中查找指定的lid等级的下一级数组
    /**
     * @param $nextlid int 当前代理等级的 lid
     * @param bool $getall
     * @return bool & array false 或 代理数据行
     */
    public function getAgentLevelForRedis($lid, $getall = true)
    {
        $redis_key = $this->redisPrefix['UAGENT'] . 'list';
        $result = false;
        $agents = $this->redisGet($redis_key);
        if (!$getall) {
            foreach ($agents['agent'] as $k => $v) {
                if (intval($v['lid']) > intval($lid)) {
                    $result = $v;
                }
            }
        } else {
            $result = $agents['agent'];
        }
        return $result;
    }
    # endregion

    # region 单个代理等级数据
    public function getAgentLevelForLid($lid)
    {
//        $redis_key = \Config\Sys::$redisKey['UAGENT'] . $lid;
//        $result = $this->redisGet($redis_key);
//        if (!$result) {
//            $db_prefix = \Config\Sys::$dbprefix;
            $sql = "SELECT * FROM `@@agentlevel` WHERE `lid`={$lid} ORDER BY `lid` ASC";
            $result = $this->db->query($sql,2);
//            $this->redisSet($redis_key, $result);
//        }
        return $result;
    }
    # endregion

    #region 生成用户的token
    /**
     * 生成用户的token
     * @param $uno
     * @param $keys
     * @return string
     */
    public function settoken($uno, $keys)
    {
        $str = md5($uno . (uniqid(md5(microtime(true)), true)) . $keys);  //生成一个不会重复的字符串
        $str = sha1($str);  //加密
        return $str;
    }
    # endregion

    # region 处理用户的VIP升级 - 与前端的API - Utility.php对应
    public function updateUserVip($uid)
    {

        $sql = "SELECT `uid`,`recharge`,`betcoin`,`userlevel` FROM `@@users` WHERE `uid`={$uid} LIMIT 1";
        $user = $this->db->query($sql, 2);

        $recharge = $user['recharge'];
        $betcoin = $user['betcoin'];

        # 下一个VIP等级
        $sql = "SELECT l.`lid`,l.`title`,l.`cointotal`,l.`rechargesum`,u.`userlevel`,l.`promotionaward` FROM `@@userlevel` l,`@@users` u WHERE l.`lid`>u.`userlevel` AND u.`uid`={$uid} ORDER BY l.`lid` ASC LIMIT 1";
        $level = $this->db->query($sql, 2);
        // var_dump($sql);
        # 比较是否适合升级的条件
        if ($recharge >= $level['rechargesum'] && $betcoin >= $level['cointotal']) {
            $sql = 'UPDATE `@@users` SET `userlevel` = ' . $level['lid'] . ' WHERE `uid` = ' . $uid . ' LIMIT 1';
            $this->db->query($sql, 1);
            # 如果晋级奖励大于 0 将记录到帐变中
            if (floatval($level['promotionaward']) > 0) {
                $this->setCoin(array(
                    'uid' => $uid,
                    'liqtype' => 29, // 晋级奖励
                    'gameid' => 0,
                    'coin' => $level['promotionaward'],
                    'ex1' => 0,
                    'ex2' => 0,
                    'ex3' => 'VIP' . $user['userlevel'] . '升至VIP' . $level['lid'] . '晋级奖励'
                ));
            }
        }
    }
    # endregion

    # region 二维数组去重
    /**
     * $arr->传入数组
     * $key->判断的key值
     **/
    public function array_unset_tt($arr, $key, $val)
    {
        //建立一个目标数组
        $res = array();
        foreach ($arr as $value) {
            //查看有没有重复项
            if (isset($res[$value[$key]]) && $res[$value[$key]] == $val) {
                unset($value[$key]);  //有：销毁
            } else {
                $res[$value[$key]] = $value;
            }
        }
        return $res;
    }
    # endregion

    # region 导出 CSV
    /**
     * @creator Jimmy
     * @data 2018/1/05
     * @desc 数据导出到excel(csv文件)
     * @param $filename 导出的csv文件名称 如date("Y年m月j日").'-test.csv'
     * @param array $tileArray 所有列名称
     * @param array $dataArray 所有列数据
     */
    public function exportToExcel($filename, $tileArray=[], $dataArray=[]){
        ini_set('memory_limit','512M');
        ini_set('max_execution_time',0);
        ob_end_clean();
        ob_start();
        header("Content-Type: text/csv");
        header("Content-Disposition:filename=".$filename);
        $fp=fopen('php://output','w');
        fwrite($fp, chr(0xEF).chr(0xBB).chr(0xBF));//转码 防止乱码(比如微信昵称(乱七八糟的))
        fputcsv($fp,$tileArray);
        $index = 0;
        foreach ($dataArray as $item) {
            if($index==1000){
                $index=0;
                ob_flush();
                flush();
            }
            $index++;
            fputcsv($fp,$item);
        }

        ob_flush();
        flush();
        ob_end_clean();
    }
    # endregion

    function get_city($ip = '')
    {
        if($ip == ''){
            $url = "http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=json";
            $ip= json_decode(@file_get_contents($url),true);
            $data = $ip;
        }else{
            $url="http://ip.taobao.com/service/getIpInfo.php?ip=".$ip;
            $ip= json_decode(@file_get_contents($url));
            if((string)$ip->code=='1'){
                return false;
            }
            $data = (array)$ip->data;
        }
        return $data['country'].'-'.$data['area'].'-'.$data['region'].'-'.$data['city'];
    }
}